package net.cyue.simple.container.injector;

import net.cyue.simple.container.annotation.Inject;
import net.cyue.simple.container.data.InjectableMetaType;
import net.cyue.simple.container.data.InstanceWrapper;
import net.cyue.simple.container.data.MetaType;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public abstract class AbstractInstanceRegistry {

    protected final Map<MetaType, InstanceWrapper> instanceWrapperMap = new ConcurrentHashMap<>();
    protected final Injector injector = new Injector(this);

    public AbstractInstanceRegistry() {
        MetaType mt = MetaTypeFactory.createInjectableMetaType(
            AbstractInstanceRegistry.class,
            "InstanceRegistry"
        );
        this.registerInstance(mt, this);
    }

    public abstract InstanceWrapper registerInstance(MetaType metaType);
    public abstract InstanceWrapper registerInstance(MetaType metaType, Object instance);

    /**
     * @param metaType MetaType
     * @return 拿不到 injectable 的实例
     */
    public InstanceWrapper getInstanceWrapper(MetaType metaType) {
        return this.instanceWrapperMap.get(metaType);
    }

    /**
     * @param clz Class
     * @return 拿不到 injectable 的实例
     */
    public InstanceWrapper getInstanceWrapper(Class<?> clz) {
        MetaType mt = new MetaType(clz, null);
        return this.instanceWrapperMap.get(mt);
    }
    public Object getInstance(MetaType metaType) {
        InstanceWrapper wrapper = this.instanceWrapperMap.get(metaType);
        if (wrapper == null) {
            return null;
        }
        return wrapper.getInstance();
    }

    public Object getInstance(Class<?> clz) {
        MetaType mt = new MetaType(clz, null);
        return this.getInstance(mt);
    }

    public Object getInjectableInstance(Inject inject) {
        if (inject == null) {
            throw new NullPointerException("inject is null");
        }
        String name = Injector.getInjectName(inject);
        if (name == null) {
            return null;
        }
        // 影响 InjectableMetaType 的 hashCode 的只有 name
        InjectableMetaType mt = new InjectableMetaType((Class<?>) null, name);
        return this.getInstance(mt);
    }
}
